package cn.coder.easyjson.util;

import java.beans.BeanInfo;
import java.beans.IntrospectionException;
import java.beans.Introspector;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Collection;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.StringTokenizer;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import cn.coder.easyjson.JSON;
import cn.coder.easyjson.JSONArray;
import cn.coder.easyjson.JSONObject;
import cn.coder.easyjson.stream.doToken;

public class ObjectUtils {
	private static final Logger log = LoggerFactory.getLogger(ObjectUtils.class);

	public static Set<Field> getDeclaredFields(Class<?> clazz) {
		Set<Field> fieldList = new HashSet<>();
		getDeclaredFields(clazz, fieldList);
		return fieldList;
	}

	private static void getDeclaredFields(Class<?> clazz, Set<Field> fieldList) {
		if (clazz != null) {
			Field[] fields = clazz.getDeclaredFields();
			for (Field field : fields) {
				if (Modifier.isFinal(field.getModifiers())) {
					continue;
				}
				fieldList.add(field);
			}
			getDeclaredFields(clazz.getSuperclass(), fieldList);
		}
	}

	public static Object cast(Class<?> type, Object obj) {
		if(obj == null || "null".equals(obj))
			return null;
		if (String.class.isAssignableFrom(type)) {
			if (obj instanceof JSONObject)
				return ((JSONObject) obj).toJson();
			if (obj instanceof JSONArray)
				return ((JSONArray) obj).toJson();
			if (obj instanceof Date) {
				SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
				return sdf.format(obj);
			}
			return obj.toString();
		}
		if (Date.class.isAssignableFrom(type)) {
			if (obj instanceof Date)
				return obj;
			log.warn("unsupport " + obj);
			return null;
		}
		if (Map.class.isAssignableFrom(type)) {
			if (obj instanceof JSONObject)
				return ((JSONObject) obj).getInnerMap();
			log.warn("unsupport " + obj);
			return null;
		}
		if (Boolean.class.isAssignableFrom(type) || boolean.class.isAssignableFrom(type))
			return Boolean.parseBoolean(obj.toString());
		if (Integer.class.isAssignableFrom(type) || int.class.isAssignableFrom(type))
			return Integer.parseInt(obj.toString());
		if (Long.class.isAssignableFrom(type) || long.class.isAssignableFrom(type)) {
			if (obj instanceof Date) {
				return ((Date) obj).getTime();
			}
			return Long.parseLong(obj.toString());
		}
		return obj;
	}

	public static void appendValue(StringBuffer temp, Object obj) {
		if (obj == null)
			temp.append("null");
		else if (obj instanceof JSONObject)
			temp.append(((JSONObject) obj).toJson());
		else if (obj instanceof JSONArray)
			temp.append(((JSONArray) obj).toJson());
		else if (Number.class.isAssignableFrom(obj.getClass()))
			temp.append(obj);
		else if (Boolean.class.isAssignableFrom(obj.getClass()) || boolean.class.isAssignableFrom(obj.getClass()))
			temp.append(Boolean.parseBoolean(obj.toString()));
		else if (Date.class.isAssignableFrom(obj.getClass())) {
			temp.append("\"");
			temp.append(cast(String.class, obj));
			temp.append("\"");
		} else if (CharSequence.class.isAssignableFrom(obj.getClass())) {
			temp.append("\"");
			String str = obj.toString();
			// 先移除转义再添加转义
			str = str.replace("\\", "\\\\").replace("\"", "\\\"");
			str = str.replace("\r", "\\r").replace("\n", "\\n").replace("\t", "\\t");
			temp.append(str);
			temp.append("\"");
		} else if (obj.getClass().isEnum()) {
			temp.append("\"");
			temp.append(obj.toString());
			temp.append("\"");
		} else if (Map.class.isAssignableFrom(obj.getClass())) {
			temp.append(JSON.parseObject(obj).toJson());
		} else if (Collection.class.isAssignableFrom(obj.getClass())) {
			temp.append(JSON.parseArray(obj).toJson());
		} else if (isSimpleBean(obj)) {
			temp.append(JSON.parseObject(obj).toJson());
		}
	}

	public static void split(String temp, String string, doToken doToken) {
		StringTokenizer tokenizer = new StringTokenizer(temp, ",");
		while (tokenizer.hasMoreTokens()) {
			doToken.exec(tokenizer.nextToken());
		}
	}

	public static boolean isSimpleBean(Object obj) {
		Class<?> aClass = obj.getClass();
		if (aClass == null || Object.class.equals(aClass)) {
			return true;
		}

		if (aClass == Date.class) {
			return false;
		}

		//

		Set<Field> declaredFields = getDeclaredFields(aClass);

		if (declaredFields.size() == 0)
			return false;

		// 循环嵌套 返回false. 无法json序列化
		for (Field field : declaredFields) {
			if (field.getType().equals(aClass)) {
				throw new RuntimeException("循环嵌套无法json序列化");
			}
		}

		try {
			BeanInfo beanInfo = Introspector.getBeanInfo(aClass);
			if (beanInfo.getPropertyDescriptors().length == 0) {
				return false;
			}
		} catch (IntrospectionException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

		// // pd属性数量必须和field数量一致
		// PropertyDescriptor[] propertyDescriptors =
		// beanInfo.getPropertyDescriptors();
		// if (propertyDescriptors.length - 1 != count) {
		// return false;
		// }
		//
		// // 属性和方法数量必须是两倍关系(get/set is/set)
		// if (count * 2 != aClass.getDeclaredMethods().length) {
		// return false;
		// }
		//
		// // 必须要有read和write方法
		// for (PropertyDescriptor pd : propertyDescriptors) {
		// // class 是其中一个propertyDescriptor
		// if (Class.class.equals(pd.getPropertyType())) {
		// continue;
		// }
		// if (pd.getWriteMethod() == null || pd.getWriteMethod() == null) {
		// return false;
		// }
		// }

		return true;
	}

}
